

<template>
  <div>

    <Category :disabled="!isHidden" />

    <div style="margin-top:30px" v-if="isHidden">
      <!-- 按钮的禁用 没有获取三号id 无法点击  -->
      <el-button type="primary" size="default" :icon="Plus" :disabled="!category3Id" @click="addAttr">新增属性</el-button>
    </div>

    <el-card v-if="isHidden" shadow="always" border :body-style="{ padding: '20px' }" stripe style="margin-top:30px">
      <!-- card body -->
      <el-table border :data="attrList">
        <el-table-column label="序号" type="index" width="80" />
        <el-table-column label="属性名称" width="150" prop="attrName">
        </el-table-column>
        <el-table-column prop="attrValueList" label="属性值名称">
          <template #default="{ row }">
            <el-tag type="danger" v-for=" item in row.attrValueList" size="default" effect="dark" @close="">
              {{ item.valueName }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="150">
          <template v-slot="{ row }">
            <el-button type="danger" size="default" :icon="Edit" @click="editAttr(row)">修改</el-button>
            <el-button type="info" size="default" :icon="Delete" @click="deleteAttrInfoListBtn(row)">删除
            </el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-card>

    <!-- 添加属性 -->
    <div style="margin-top:30px" v-else>
      <el-form ref="form" :inline="true">
        <el-form-item label="属性名">
          <el-input placeholder="请输入属性名" v-model="newAttrData.attrName"></el-input>
        </el-form-item>
      </el-form>

      <div>
        <!-- 输入框没有值则不可以添加属性值 -->
        <el-button type="primary" :disabled="!newAttrData.attrName" @click="addAttrValue">添加属性值</el-button>
        <el-button @click="cancel">取消</el-button>
      </div>
      <el-table :data="newAttrData.attrValueList" stripe :style="{ marginTop: '30px' }">
        <el-table-column label="序号" type="index" width="50" />

        <el-table-column prop="valueName" label="属性值名称">
          <template v-slot="{ row, $index }">
            <el-input v-if="row.isEdit" ref="editEle" v-model="row.valueName" placeholder="请输入要添加的属性值"
              @blur="changeToLook(row, $index)" @focus="saveOldValue(row)">
            </el-input>
            <span :style="{ display: 'inline-block', width: '70%' }" v-else @click="changeToEdit(row)">{{ row.valueName
            }}</span>
          </template>
        </el-table-column>

        <el-table-column label="操作">
          <template v-slot="{ $index }">
            <!-- 气泡确认框 -->
            <el-popconfirm title="你确定要删除这个属性吗?" @confirm="deleteAttrValue($index)">
              <template #reference>
                <el-button type="danger" size="small" icon="ele-Delete"></el-button>
              </template>
            </el-popconfirm>
          </template>
        </el-table-column>
      </el-table>
      <div>
        <!-- 属性值列表没有值 不可以保存  -->
        <el-button type="primary" :disabled="newAttrData.attrValueList.length <= 0 || !newAttrData.attrName"
          @click="saveOrChange">保存</el-button>
        <el-button @click="cancel">取消</el-button>
      </div>
    </div>


  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';

export default defineComponent({
  name: 'Attr',
});
</script>

<script setup lang="ts">
  import { ElMessage } from "element-plus";
import { Plus, Delete, Edit } from "@element-plus/icons-vue";
import { watch, ref, nextTick } from 'vue'
import { storeToRefs } from "pinia";
import useattrStore from '@/stores/attr'
//类型
import type { attrListType, attrubuteType, valueType } from "@/api/attr";
//请求
import { getAttrInfoList, addOrchangeAttrInfoList, deleteAttrInfoList } from "@/api/attr";

//lodash 
import cloneDeep from "lodash/cloneDeep";

/* attr对应-store仓库 */
const attrStore = useattrStore()
const { category3Id, category2Id, category1Id } = storeToRefs(attrStore)
//存放三级分类得到的属性列表
const attrList = ref<attrListType>([]);

//封装请求api
const getAttrList = async () => {
  const result = await getAttrInfoList(category1Id.value as number, category2Id.value as number, category3Id.value as number)
  attrList.value = result
}

// 1。获取属性列表的逻辑
/* 监听第三级分类的改变，然后请求属属性列表 */
watch(category3Id, (newValue) => {
  if (!newValue) {
    /* 如果没有三级列表id ， 不用显示 下面的属性列表 */
    attrList.value = []
    return
  }
  getAttrList()
  /* immediate 切换路由重新加载  立即监听变化 */
}, { immediate: true })

//2.添加平台属性的逻辑
//响应式控制显示隐藏
const isHidden = ref(true)
//保存新增属性初始值
const newAttrData = ref<attrubuteType>({
  attrName: '',
  categoryId: category3Id.value as number,
  categoryLevel: 3,
  attrValueList: []
})
//切换添加平台属性
const addAttr = () => {
  //先切换到新增页
  isHidden.value = false
  //每次新增的时候，清空上一次可能残留的数据（重新给newAttrData赋值初始值）
  newAttrData.value = {
    attrName: "",
    categoryId: category3Id.value as number, //固定是category3Id
    categoryLevel: 3, //固定是3
    attrValueList: [],
  };
}
//返回获取属性按钮
const cancel = () => {
  //先切换到属性列表页
  isHidden.value = true
}

//给新增的属性 添加属性值的事件的回调函数
const addAttrValue = () => {
  //创建一个属性值的数据
  const newAttrValue = ref({
    valueName: '',
    attrId: newAttrData.value.id, //当前属性值所在的属性的id(就算是新增,属性没有id,我们也要关联,将来后端添加id的时候,我就有值了)
    isEdit: true, //我们给新增的属性值数据中添加一个逻辑 isEdit代表当前模式是否是编辑模式(新增的数据肯定是编辑模式)
  })
  //把新增的属性值数据 添加到新属性 属性值列表的数组中
  newAttrData.value.attrValueList.push(newAttrValue.value)
  //在添加属性的时候也要自动获取焦点 如果不获取焦点 则出现 一堆输入框 影响性能
  nextTick(() => {
    editEle.value.focus();
  });
}

//在属性列表中修改某个属性的事件方法
const editAttr = (row: attrubuteType) => {
  //先切换到新增或者添加属性页
  isHidden.value = false;
  //在回调数据的时候,我们遍历row中的所有的属性值,给每一个属性值对象添加一个isEdit值为false(因为回填的数据默认是查看模式)
  const cloneRow = cloneDeep(row);
  cloneRow.attrValueList.forEach((item) => {
    item.isEdit = false;
  });
  //回填数据,因为视图和初始新增数据的newAttrData进行深度绑定,所以回填的时候,直接把被修改的数据赋值给newAttrData即可
  newAttrData.value = cloneRow
};

/* 
  点击的时候 什么时候是点击 获取焦点的时候是点击   变为 input框
  失去焦点的时候 变为 span
*/

//创建一个数据用来保存编辑模式的input元素
const editEle = ref();
//变为编辑模式
//切换查看模式到编辑模式 给span绑定的点击事件回调函数
const changeToEdit = (row: valueType) => {
  //row是当前属性值所在的数据,把当前的数据中的isEdit变为true
  row.isEdit = true
  //让当前的表单自动获取焦点(操作真实DOM的时候,看情况要放在nextTick中,等DOM加载完成才能执行)
  nextTick(() => {
    editEle.value.focus();
  })
}


let oldAttrValueName = "";
//给编辑模式绑定获取焦点事件,保存旧值
const saveOldValue = (row: valueType) => {
  //先把当前的旧值保存起来
  oldAttrValueName = row.valueName;
  // console.log(oldAttrValueName);
};

//切换到查看模式的事件回调函数
const changeToLook = (row: valueType, $index: number) => {
  //row是当前属性值所在的数据,把当前的数据中的isEdit变为false
  row.isEdit = false;

  //判断输入的是否为空
  if (!row.valueName.trim()) {
    //如果输入为空,并且旧值也为空,那么说明当前是新增属性值,并且用户没有填,直接删除
    if (!oldAttrValueName) {
      newAttrData.value.attrValueList.splice($index, 1);
    } else {
      //如果有旧值,则直接把旧值还给用户,并且把旧值清空
      row.valueName = oldAttrValueName;
    }
  }

  //判断用户输入的是否有重复选项,如果有,则恢复
  let isRepeat = newAttrData.value.attrValueList.some((item) => {
    //如果自己比较自己的时候,我们跳过(不挑过的话,永远isRepeat为true)
    if (item === row) {
      return;
    }
    return item.valueName === row.valueName;
  });

  //判断在数据列表中除了row自身以外,还有没有谁的valueName值和row的相等,如果有,则恢复旧值
  if (isRepeat) {
    row.valueName = oldAttrValueName;
  }
  //统一在失去焦点事件结束的时候 清空旧值
  oldAttrValueName = "";
};

//在修改属性中删除单条数据
const deleteAttrValue = ($index: number) => {
  newAttrData.value.attrValueList.splice($index, 1);
  getAttrList()
}

//保存或者修改
const saveOrChange = async () => {
  //我们自己给newAttrData 中的数据 添加了 isEdit属性 不需要发送过去
  newAttrData.value.attrValueList.forEach(item => {
    delete item.isEdit
  })
  //输入框为空,不能提交
  if (!newAttrData.value.attrValueList.length) {
    ElMessage.error("属性列表不能为空")
    /* 防止继续往下执行报错 */
    return
  }
  try {
    await addOrchangeAttrInfoList(newAttrData.value)
    ElMessage.success("添加属性列表成功")
    //返回获取属性列表界面
    isHidden.value = true;
    //重新发送请求，刷新界面
    getAttrList()
  } catch (e) {
    ElMessage.error("添加属性列表失败")
  }
}
//删除某个属性按钮
const deleteAttrInfoListBtn = async (row: attrubuteType) => {
  try {
    await deleteAttrInfoList(row.id as number)
    ElMessage.success("删除成功")
    //重新发送请求，刷新界面
    getAttrList()
  } catch (e) {
    ElMessage.error("删除失败")
  }
}

</script>